﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.ComponentModel;
using System.Linq;


namespace ExtensionsLib.Dictionary
{

    public static class DictionaryExtensions
    {

     


        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map">The map.</param>
        /// <param name="key">The key.</param>
        /// <param name="_default">The _default.</param>
        /// <returns></returns>
        public static T GetValue<T>(this IDictionary<string, string> map, string key, T _default)
        {
            if (map.ContainsKey(key))
            {
                string value = map[key];
                if (false == String.IsNullOrEmpty(value))
                {
                    return Cast<T>(value);
                }
                else
                {
                    return _default;
                }
            }
            else
            {
                return _default;
            }
        }


        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map">The map.</param>
        /// <param name="key">The key.</param>
        /// <param name="_default">The _default.</param>
        /// <returns></returns>
        public static T GetValue<T>(this IDictionary<string, object> map, string key, T _default)
        {
            if (map.ContainsKey(key))
            {
                object value = map[key];
                if (null != value)
                {
                    return Cast<T>(value);
                }
                else
                {
                    return _default;
                }
            }
            else
            {
                return _default;
            }
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="map">The map.</param>
        /// <param name="key">The key.</param>
        /// <param name="_default">The _default.</param>
        /// <returns></returns>
        public static T GetValue<T>(this Dictionary<string, object> map, string key, T _default)
        {
            if (map.ContainsKey(key))
            {
                object value = map[key];
                if (null != value)
                {
                    return Cast<T>(value);
                }
                else
                {
                    return _default;
                }
            }
            else
            {
                return _default;
            }
        }


        /// <summary>
        /// Casts the specified value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static T Cast<T>(object value)
        {
            if (value == DBNull.Value || value == null) { return default(T); }
            if (value.GetType() == typeof(T)) { return (T)value; }
            if (typeof(T).IsEnum) { return (T)Enum.Parse(typeof(T), (string)value, true); }
            if (value is IConvertible)
            {
                Type conversionType = typeof(T);
                if (IsNullableType(typeof(T)))
                {
                    NullableConverter nullableConverter = new NullableConverter(typeof(T));
                    conversionType = nullableConverter.UnderlyingType;
                    return (T)Convert.ChangeType(value, conversionType);
                }
                else
                {
                    return (T)Convert.ChangeType(value, conversionType);
                }
            }
            try
            {
                return (T)value;
            }
            catch (Exception e)
            {
                throw new Exception("Conversion of '" + value.ToString() + "' to type [" + typeof(T).Name + "] failed!", e);
            }
        }

        /// <summary>
        /// Determines whether [is nullable type] [the specified type].
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>
        /// 	<c>true</c> if [is nullable type] [the specified type]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
        }


    }
}


